/*
 * Licensed Materials - Property of IBM
 *
 * OCO Source Materials
 *
 * (C) Copyright IBM Corp. 2011, 2012 All Rights Reserved
 *
 * The source code for this program is not published or other-
 * wise divested of its trade secrets, irrespective of what has
 * been deposited with the U.S. Copyright Office.
 */
package com.ibm.cfs.api.marshallers;

import java.util.HashSet;
import java.util.Set;

import com.ibm.cfs.api.Messages;
import com.ibm.cfs.api.constants.ResourceRepresentationConstants;
import com.ibm.cfs.api.resources.MetricValueResource;
import com.ibm.cfs.api.resources.MetricValuesResource;
import com.ibm.cfs.core.resources.MetricValue;
import com.ibm.cfs.core.resources.VirtualServer.Architecture;
import com.ibm.cfs.json.JSONArray;
import com.ibm.cfs.json.JSONObject;
import com.ibm.cfs.util.io.Marshaller;
import com.ibm.cfs.util.io.MarshallerException;

/**
 * @author Yi Cong Lu(Eason)
 *
 */
public class MetricValuesResourceMarshaller implements Marshaller<MetricValuesResource> {

    /* (non-Javadoc)
     * @see com.ibm.cfs.util.io.Marshaller#marshal(java.lang.Object)
     */
    @Override
    public String marshal(MetricValuesResource resources) throws MarshallerException {
        /*
         * This is what we are going to produce:
         * 
         *  {
         *     "stats":[
         *         {
         *             "architecture": "Power",
         *             "resources":[
         *                 {"id": "usageCPU", "label": "CPU", "value":"100"},
         *                 {"id": "usageMemory","label": "Memory", "value":"113250"},
         *                 {"id": "usageDisk","label": "Storage", "value":"1012310"}
         *             ]
         *         },
         *         {
         *             "architecture": "x86",
         *             "resources":[
         *                 {"id": "usageCPU", "label": "CPU", "value":"100"},
         *                 {"id": "usageMemory","label": "Memory", "value":"113250"},
         *                 {"id": "usageDisk","label": "Storage", "value":"1012310"}
         *             ]
         *         }
         *     ],
         *     "uri":"http://localhost:8080/cfs/api/usage"
         *  }
         *       
         */
       try {
            JSONObject jsonObj = new JSONObject();
            jsonObj.put(ResourceRepresentationConstants.URI, resources.getUri());

            JSONArray jsonStatsData = new JSONArray();
            jsonObj.put(ResourceRepresentationConstants.STATS, jsonStatsData);

            Set<Architecture> architectureSet = new HashSet<Architecture>();
            for (MetricValueResource resource : resources.getResources()) {
            	MetricValue metric = resource.getBaseObject();
            	if (!architectureSet.contains(metric.getArchitecture())) {
            		architectureSet.add(metric.getArchitecture());
            	}
            }
            for (Architecture architecture : architectureSet) {
                JSONObject architectureJsonObj = new JSONObject();
                if (architecture != null) {
                	architectureJsonObj.put(ResourceRepresentationConstants.ARCHITECTURE, architecture.name());
                }
                JSONArray resourceJsonArray = new JSONArray();
                architectureJsonObj.put(ResourceRepresentationConstants.RESOURCES, resourceJsonArray);
                jsonStatsData.put(architectureJsonObj);
                for (MetricValueResource resource : resources.getResources()) {
                    MetricValue metric = resource.getBaseObject();
                    if (architecture == null ? metric.getArchitecture() == null : architecture.equals(metric.getArchitecture())) {
                        JSONObject jsonMetric = new JSONObject();
                        jsonMetric.put(ResourceRepresentationConstants.ID, metric.getType());
                        jsonMetric.put(ResourceRepresentationConstants.LABEL, metric.getDisplayName());
                        //Change the double value to string, so that it can output the value of the double like NaN correctly .
                        if (metric.getResourceValue() != null) {
                            jsonMetric.put(ResourceRepresentationConstants.VALUE, metric.getResourceValue().toString());
                        } else {
                            jsonMetric.put(ResourceRepresentationConstants.VALUE, Double.NaN);
                        }
                        resourceJsonArray.put(jsonMetric);
                    }
                }
            }
            return jsonObj.toString();
        } catch (Exception e) {
            throw new MarshallerException(e, Messages.getInstance(), "marshalling.error", e.getMessage());  //$NON-NLS-1$
        }
    }

}
